﻿<!-- /components/SearchList.vue -->
<template>
  <div class="search-list">
    <!-- 加载态 -->
    <template v-if="loading">
      <el-skeleton v-for="n in 6" :key="n" animated class="skeleton">
        <template #template>
          <el-skeleton-item variant="h1" style="width: 60%; height: 22px; margin-bottom: 12px" />
          <div style="display: flex; gap: 16px">
            <el-skeleton-item variant="image" style="width: 120px; height: 80px; border-radius: 6px" />
            <el-skeleton-item variant="p" style="flex: 1; height: 80px" />
          </div>
        </template>
      </el-skeleton>
    </template>

    <!-- 列表 -->
    <template v-else-if="list.length">
      <div v-for="row in list" :key="row.id" class="search-item" @click="handleClick(row)">
        <div class="item-title" v-html="renderTitle(row.title, innerKeywords)"></div>

        <div class="item-main">
          <img v-if="row._cover" class="item-cover" :src="row._cover" alt="" />
          <div class="item-desc">{{ textSnippet(row.content) }}</div>
        </div>

        <div class="item-meta">
          <span class="date">{{ formatDate(row.updateTime) }}</span>
        </div>
      </div>
    </template>

    <!-- 空 -->
    <div v-else class="empty-state">
      <img class="empty-image" :src="emptyImage" alt="暂无内容" />
      <div class="empty-text">暂无内容，敬请期待</div>
    </div>
  </div>
</template>

<script setup>
  import { ref, watch, onMounted, defineExpose } from "vue";
  import emptyImage from "@/assets/setting/img_empty.png";

  const props = defineProps({
    /** 父级也可以直接传关键词；或用 ref.goSearch({ keywords }) 主动触发 */
    keywords: { type: String, default: "" },
  });
  const emit = defineEmits(["select"]);

  const innerKeywords = ref(props.keywords || "");
  const loading = ref(false);
  const list = ref([]);

  /* 公开方法：触发搜索 */
  async function goSearch({ keywords } = {}) {
    innerKeywords.value = (keywords ?? innerKeywords.value)?.trim();
    if (!innerKeywords.value) {
      list.value = [];
      return;
    }
    await fetchList();
  }
  defineExpose({ goSearch });

  /* 父级改变 :keywords 时联动搜索 */
  watch(
    () => props.keywords,
    v => {
      innerKeywords.value = (v || "").trim();
      if (!innerKeywords.value) {
        list.value = [];
      } else {
        goSearch({ keywords: innerKeywords.value });
      }
    }
  );

  /* 首次带关键词则搜一次 */
  onMounted(() => {
    if (innerKeywords.value) goSearch({ keywords: innerKeywords.value });
  });

  /* 调你们的接口：Api.service.GetSelectContent */
  async function fetchList() {
    try {
      loading.value = true;
      const res = await Api.service.GetSelectContent({ title: innerKeywords.value });
      // 支持两种后端包裹方式：{code,message,data:[...]} 或直接数组
      const data = res?.data ?? res;
      const arr = Array.isArray(data?.data) ? data.data : Array.isArray(data) ? data : [];

      list.value = (arr || []).map(it => ({
        id: it.id,
        title: it.title || "",
        content: it.content || "",
        updateTime: it.updateTime || it.updatedAt || "",
        // 优先接口给的封面；否则从 content 里取第一张图
        _cover: it.coverUrl || pickFirstImg(it.content),
        // 其它字段原样透传，父级需要可用
        ...it,
      }));
    } catch (e) {
      console.error("[GetSelectContent] error:", e);
      list.value = [];
    } finally {
      loading.value = false;
    }
  }

  /* 交互 */
  function handleClick(row) {
    emit("select", row);
  }

  /* 工具 */
  function renderTitle(text, kw) {
    const safe = escapeHtml(text || "");
    if (!kw) return safe;
    try {
      const reg = new RegExp(escapeReg(kw), "gi");
      return safe.replace(reg, m => `<em class="kw">${m}</em>`);
    } catch {
      return safe;
    }
  }
  function textSnippet(html = "", max = 120) {
    const txt = String(html)
      .replace(/<[^>]+>/g, "")
      .replace(/\s+/g, " ")
      .trim();
    return txt.length > max ? txt.slice(0, max) + "…" : txt;
  }
  function pickFirstImg(html = "") {
    const m = String(html).match(/<img[^>]+src=["']?([^"'>\s]+)["']?[^>]*>/i);
    return m ? m[1] : "";
  }
  function escapeHtml(s = "") {
    return s
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&#39;");
  }
  function escapeReg(s = "") {
    return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
  }
  function formatDate(val) {
    if (!val) return "";
    const d = new Date(String(val).replace(/-/g, "/"));
    const mm = String(d.getMonth() + 1).padStart(2, "0");
    const dd = String(d.getDate()).padStart(2, "0");
    return `${mm}-${dd}`;
  }
</script>

<style scoped lang="scss">
  .search-list {
    padding: 8px 0 24px;
    min-height: 100%;
    height: auto;
    position: relative;
  }
  .skeleton {
    margin-bottom: 18px;
  }

  .search-item {
    background: var(--bg);
    border-bottom: 1px solid #eef0f3;
    padding: 16px;
    cursor: pointer;
    transition: background-color 0.15s ease;

    // &:hover {
    //   background: var(--bd9);
    // }

    .item-title {
      font-size: 16px;
      line-height: 22px;
      font-weight: 600;
      color: #15194d;
      margin-bottom: 10px;
      :deep(.kw) {
        color: var(--bd);
      }
      &:hover {
        color: var(--bd);
      }
    }

    .item-main {
      display: flex;
      gap: 16px;
      align-items: flex-start;
      .item-cover {
        width: 120px;
        height: 80px;
        object-fit: cover;
        border-radius: 6px;
        flex-shrink: 0;
      }
      .item-desc {
        flex: 1;
        color: #737594;
        line-height: 22px;
        display: -webkit-box;
        line-clamp: 3;
        -webkit-line-clamp: 3;
        -webkit-box-orient: vertical;
        overflow: hidden;
        word-break: break-all;
      }
    }

    .item-meta {
      margin-top: 10px;
      color: #a6a7b3;
      font-size: 12px;
    }
  }

  /* 空状态样式 */
  .empty-state {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
  }

  .empty-image {
    width: 120px;
    height: 100px;
    margin-bottom: 8px;
    object-fit: contain;
  }

  .empty-text {
    font-size: 14px;
    color: var(--ct3);
    text-align: center;
  }
</style>
